/* 
 *  Copyright 2008 CodeMagi, Inc.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.codemagi.util;

//import java.rmi.server.UID;
import java.net.URL;
import java.net.URLConnection;
import java.io.DataInputStream;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Utility class for getting a unique 32-digit hex identifier.
 *
 * @author Dieter Wimberger (original author)
 * @see    http://jwma.sourceforge.net/
 * @author August Detlefsen for CodeMagi, Inc.
 * @version 1.0
 * @deprecated Use java.util.UUID instead. This class simply wraps UUID.
 */
public class UIDGenerator {

    /*
    private static SecureRandom m_Random;
    private static int m_ReseedCounter = 0;
    
    //create seeded random
    static {
	m_Random = new SecureRandom();
	seedRandom();
    }
    */
    
    /**
     * Returns a UID (unique identifier) as <tt>String</tt>.
     * The identifier represents the MD5 hashed combination
     * of a <tt>java.rmi.server.UID</tt> instance, a random padding of
     * <tt>RANDOM_PADDING</tt> length, it's identity hashcode and
     * <tt>System.currentTimeMillis()</tt>.
     *
     * @return the UID as <tt>String</tt>.
     * @deprecated Use java.util.UUID instead
     */
    public static final synchronized String getUID() {

	return StringUtils.replace(java.util.UUID.randomUUID().toString(), "-", "");

	/*
	byte[] buffer = new byte[RANDOM_PADDING];
	String u = new UID().toString();
	int i = System.identityHashCode(u);
	long d = System.currentTimeMillis();
	//create random padding
	m_Random.nextBytes(buffer);
	u = u + new String(buffer);
	
	if (m_ReseedCounter == RANDOM_RESEED) {
	    seedRandom();
	    m_ReseedCounter = 0;
	} else {
	    m_ReseedCounter++;
	}

	//	System.out.println("u: " + u + " i: " + i + " d: " + d);

	//	return MD5.hash(u + i + d);
	return SHA1(u + i + d);
	*/
    }//getUID
    
    /**
     * If the <tt>HotBits</tt> Server is available, <tt>Random</tt>
     * will be seeded with a real random long.
     * <p>
     * <a href="http://www.fourmilab.ch/hotbits/">HotBits</a> is located
     * at Fermilab, Switzerland.
     *
     * @deprecated Calling this method has no effect
     */
    public static final void seedRandom() {
	/*
	try {
	    URL url = new URL(HOTBITS_URL);

	    //set some connection params so we do not wait forever for the hotbits server
	    URLConnection conn = url.openConnection();
	    conn.setConnectTimeout(4000);
	    conn.setReadTimeout(4000);

	    //attempt to read random bits from the server
	    DataInputStream din = new DataInputStream(conn.getInputStream());
	    m_Random.setSeed(din.readLong());
	    din.close();
	} catch (Exception ex) {
	    //use what is available
	    m_Random.setSeed(System.currentTimeMillis());
	}
	*/
    }//seedRandom


    /**
     * Computes the hex-encoded SHA-1 hash of the input String. 
     */
    public static String SHA1(String text) {
        try {
            MessageDigest md;
            md = MessageDigest.getInstance("SHA-1");
            byte[] sha1hash = new byte[40];
	    byte[] textBytes = text.getBytes("iso-8859-1");
	    System.out.println("textBytes: " + textBytes);
		    
            md.update(textBytes, 0, text.length());
            sha1hash = md.digest();
            return convertToHex(sha1hash);
        } catch (NoSuchAlgorithmException nsae) {
            //this should never happen
        } catch (UnsupportedEncodingException uee) {
            //this should never happen
	} catch (IllegalArgumentException iae) {
	    System.out.println("text: " + text);
            System.out.println("length: " + text.length());
	    
	    return getUID(); //HACK!!! - start the whole process again
	}

        //fallback just to make the compiler happy
        return convertToHex(text.getBytes());
    }

    private static String convertToHex(byte[] data) {
        StringBuilder buf = new StringBuilder();
        for (int i = 0; i < data.length; i++) {
            int halfbyte = (data[i] >>> 4) & 0x0F;
            int two_halfs = 0;
            do {
                if ((0 <= halfbyte) && (halfbyte <= 9))
                    buf.append((char) ('0' + halfbyte));
                else
                    buf.append((char) ('a' + (halfbyte - 10)));
                halfbyte = data[i] & 0x0F;
            } while(two_halfs++ < 1);
        }
        return buf.toString();
    }

    /**
     * Main method for testing only!
     */    
    public static final void main(String[] args) {
	java.util.HashSet uids = new java.util.HashSet();
	int i = 0;
	long start = System.currentTimeMillis();
	while (i < 1000000) {
	    String uid = getUID();
	    System.out.println(uid);
	    
	    boolean alreadyExists = uids.add(uid);

	    if (!alreadyExists) {
		System.out.println("PRE-EXISTING UID FOUND! position: " + i);
		break;
	    }

	    i++;
	}
	long stop = System.currentTimeMillis();
	System.out.println("Time =" + (stop - start) + "[ms]");
    }//main
    
    public static final int RANDOM_PADDING = 256;
    public static final int RANDOM_SEED_LENGTH = 6;
    public static final int RANDOM_RESEED = 1000;
    
    public static final String HOTBITS_URL =
	"http://www.fourmilab.ch/cgi-bin/uncgi/Hotbits?nbytes=" +
	RANDOM_SEED_LENGTH +
	"&fmt=bin";
    
}//UIDGenerator
